/*
 *  objects.cpp
 *  joosVM
 *
 *  Created by Smári Waage on 11.6.2009.
 *  Copyright 2009 smari.org. All rights reserved.
 *
 *  This program is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU General Public License
 *  as published by the Free Software Foundation; either version 2
 *  of the License, or (at your option) any later version.
 *  
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *  
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. *
 */

#include "objects.h"

int HeapObject::size(){
	
	switch (getInternalType()->value()) {
	
		case IType_StaticArray: return ((StaticArray*)this)->staticarray_size();
		case IType_ByteArray: return ((ByteArray*)this)->bytearray_size();
		case IType_String: return ((String*)this)->string_size();
		case IType_HashTable: return ((HashTable*)this)->hashtable_size();
			
		case IType_MethodArea: return ((MethodArea*)this)->methodarea_size();
		case IType_JField: return ((JField*)this)->fielddata_size();
		case IType_JStaticField: return ((JStaticField*)this)->staticfielddata_size();
		case IType_JAbstractMethod: return ((JAbstractMethod*)this)->abstractmethoddata_size();
		case IType_JMethod: return ((JMethod*)this)->methoddata_size();
		case IType_JType: return ((JType*)this)->typedata_size();
		case IType_Instance: return ((Instance*)this)->instance_size();
		case IType_TaggedArray: return ((TaggedArray*)this)->taggedarray_size();
		case IType_TaggedValue: return ((TaggedValue*)this)->taggedvalue_size();
		case IType_HeapPrimitive: return ((HeapPrimitive*)this)->heapprimitive_size();
		case IType_HeapDblPrimitive: return ((HeapDblPrimitive*)this)->heapdblprimitive_size();
		
			
		case IType_Frame: return ((Frame*)this)->frame_size();
		case IType_Stack: return ((Stack*)this)->stack_size();
#if TRACE_JIT
		case IType_TraceTreeObject: return ((TraceTreeObject*)this)->tracetreeobject_size();
#endif
	}
	return 0;
}

Pointer* HeapObject::forward(Pointer** nHP){
	if(isHeapObject()){
		Pointer* fwaddr = field(kfwAddress);
		if(fwaddr == NULL){
			int len = size();
			REQUIRE(len%4==0)
			//memcpy(*nHP, address(), len);
			
			fwaddr = (*nHP)+1;
			for(int i=kInternalTypeOffset;i<len;i+=kPointerSize){	
				((HeapObject*)fwaddr)->setField(i,field(i));
			}
			for(int i=kInternalTypeOffset;i<len;i+=kPointerSize){
				ENSURE(field(i) == ((HeapObject*)fwaddr)->field(i))
			}
			
			setField(kfwAddress,fwaddr);// setField(kfwAddress,fwaddr);
			*nHP = *nHP + len;
			//((HeapObject*)fwaddr)->setField(kfwAddress, NULL);
		}
		ENSURE(((HeapObject*)fwaddr)->field(kfwAddress) == NULL)
		return fwaddr;// using the InternalType field to store the fwAddress
	}else {
		return this;
	}

	
}
void HeapObject::scan(Pointer** nHP){
	
	REQUIRE(Heap::isGCAddressOk(this))
	switch ( getInternalType()->value()) {
		case IType_StaticArray: ((StaticArray*)this)->staticarray_scan(nHP); break;
		case IType_ByteArray: ((ByteArray*)this)->bytearray_scan(nHP); break;
		case IType_String: ((String*)this)->string_scan(nHP); break;
		case IType_HashTable: ((HashTable*)this)->hashtable_scan(nHP); break;
		case IType_MethodArea: ((MethodArea*)this)->methodarea_scan(nHP); break;
		case IType_JField: ((JField*)this)->fielddata_scan(nHP); break;
		case IType_JStaticField: ((JStaticField*)this)->staticfielddata_scan(nHP); break;
		case IType_JAbstractMethod: ((JAbstractMethod*)this)->abstractmethoddata_scan(nHP);break;
		case IType_JMethod: ((JMethod*)this)->methoddata_scan(nHP);break;
		case IType_JType: ((JType*)this)->typedata_scan(nHP);break;
		case IType_Instance: ((Instance*)this)->instance_scan(nHP);break;
		case IType_Frame: ((Frame*)this)->frame_scan(nHP);break;
		case IType_Stack: ((Stack*)this)->stack_scan(nHP);break;
		case IType_TaggedArray: ((TaggedArray*)this)->taggedarray_scan(nHP);break;
		case IType_TaggedValue: ((TaggedValue*)this)->taggedvalue_scan(nHP);break;
		case IType_HeapPrimitive: ((HeapPrimitive*)this)->heapprimitive_scan(nHP);break;
		case IType_HeapDblPrimitive: ((HeapDblPrimitive*)this)->heapdblprimitive_scan(nHP);break;
#if TRACE_JIT
		case IType_TraceTreeObject: ((TraceTreeObject*)this)->tracetreeobject_scan(nHP);break;
#endif
	}
	//jump  to the next object if there is one.
	HeapObject* next = this + size(); //should realy make the whole of this an iterative process to reduce the c callstack, though it will be fine.
	if((*nHP) > next->address()){
		next->scan(nHP);
	}//I know the next object is a HeapObject, becuase only HeapObjects live out in heap space, smi's only live inside of HeapObjects.	
}


int Array::array_length() {
	switch (getInternalType()->value()) {
		case IType_StaticArray: return ((StaticArray*)this)->array_length();
		case IType_ByteArray: return ((ByteArray*)this)->array_length();
		case IType_String: return ((String*)this)->string_length();
		case IType_TaggedArray: return ((TaggedArray*)this)->array_length();
		default: 
			printf("Error trying to determin length on a non array");
			exit(1);
	}
	return 0;
}


